﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data;
using System.Xml;
using SdmxMl.Common;
using SdmxMl.Multiplexor;
using SdmxMl.Structure;
using SdmxMl.Manager;

namespace SdmxMl.Manager
{
    /// <summary>
    /// Manages a transfer of all Metadata used by a group into a folder organisation
    /// that mimic TinyRegistry folder requirements
    /// </summary>
    public class GroupMetaTransfer
    {
        // Artefact list document name
        private static string DirInfoFile = "dirInfo.sms";

        private string groupId;
        private string rootDir;
        private IRegistry muxReg;
        private ProxyService proxyGroup;
        private Dictionary<SdmxArtefactType, DataTable> dicoDirInfo;
        private Dictionary<SdmxArtefactType, DataTable> dicoDirTreated;
        private Dictionary<string, string> dicoTreatedArtefact;
        #region Constructor

        /// <summary> C'tor </summary>
        /// <param name="root">Root directory or artefacts</param>
        /// <param name="id">ID of Meta Group owner </param>
        /// <param name="mux"> Registry accessor instance</param>
        public GroupMetaTransfer(string root, string id, IRegistry mux)
        {
            rootDir = root;
            groupId = id;
            muxReg = mux;

            // Check if folder is empty
            if (Directory.Exists(rootDir))
            {
                var folder = new DirectoryInfo(rootDir);
                if (folder.GetFileSystemInfos().Length > 0)
                    throw new ApplicationException("Destination folder is not empty, please choose another one");
            }
            else
                    throw new ApplicationException("Destination folder does not exist");
           

            // Check registry accessor
            if (muxReg == null || muxReg.RunningOK == false)
                throw new ArgumentException("Registry accessor invalid or on error");

            proxyGroup = muxReg.GetProxyForGroup(groupId);
            dicoDirInfo = new Dictionary<SdmxArtefactType, DataTable>(16);
            dicoDirTreated = new Dictionary<SdmxArtefactType, DataTable>(16);
            dicoTreatedArtefact = new Dictionary<string, string>(1024);
        }

        #endregion


        // Load dirInfo images of group registry
        public void LoadDirInfoImages()
        {
            GetDirectoryInformations();

            foreach (SdmxArtefactType arType in Enum.GetValues(typeof(SdmxArtefactType)))
            {
                if (arType == SdmxArtefactType.None)
                    continue;

                DataTable tbArtefact = dicoDirInfo[arType];

                foreach (DataRow row in tbArtefact.Rows)
                {
                    ArtefactRefTyped art = new ArtefactRefTyped(arType, row["ID"].ToString(), row["AI"].ToString(), row["Ver"].ToString());
                    DescendantMgr mg = new DescendantMgr(art, DescendantMode.Descendants);
                    mg.ArtefactToManageEventExposed += new ArtefactToManageEvent(mg_ArtefactToManageEventExposed);
                    mg.Explore();
                    // for all fetched artefacts
                    foreach (ArtefactManager am in mg.SmContainer.ArtefactManagerDico.Values)
                    {
                        foreach (Artefact a in am.ArtefactList)
                        {
                            // save file and update table if not yet in

                            string subDir = rootDir + "\\" + a.ArType.ToString();
                            if (Directory.Exists(subDir) == false)
                                Directory.CreateDirectory(subDir);

                            XmlDocument xDoc = am.GetAsDocument(a);
                            xDoc.Save(subDir + "\\" + a.FullIdent + ".xml");
                            dicoTreatedArtefact.Add(a.ArType.ToString() + "+" + a.FullIdent, string.Empty);

                            CreateRow(a, dicoDirTreated[a.ArType]);

                        }
                    }

                }

            }

            // Now write the matching DirInfo
            foreach (SdmxArtefactType arType in Enum.GetValues(typeof(SdmxArtefactType)))
            {
                if (arType == SdmxArtefactType.None)
                    continue;

                string subDir = rootDir + "\\" + arType.ToString();
                if (Directory.Exists(subDir) == false)
                    Directory.CreateDirectory(subDir);

                DataSet ds = new DataSet();
                ds.Tables.Add(dicoDirTreated[arType]);
                ds.WriteXml(subDir + "\\" + DirInfoFile, XmlWriteMode.WriteSchema);
            }
       }

        /// <summary>Create row holding artefact basic information</summary>
        /// <param name="a">the artefact</param>
        /// <param name="tb">the table where to create new info</param>
        private void CreateRow(Artefact a, DataTable tb)
        {
            string user = muxReg.UserId;

            // Create row 
            DataRow newRow = tb.Rows.Add(new object[] {
                    a.Id, 
                    a.Version,
                    a.AgencyId,
                    });


            // Default diffusion status at creation
            newRow["DI"] = "1";

            // Update names
            foreach (string lg in LangSupport.SupportedLanguages)
                newRow["Name_" + lg] = a.Name.GetForLanguage(lg);
            // and validity
            newRow["VF"] = a.ValidFrom == string.Empty ? null : a.ValidFrom;
            newRow["VT"] = a.ValidTo == string.Empty ? null : a.ValidTo;

            // and IsFinal
            newRow["IF"] = a.IsFinal;

            // and update date and updated by
            newRow["LU"] = DateTime.Now.ToString("s");
            newRow["UB"] = user;

            // and ensure no more check out
            newRow["CO"] = null;
            newRow["CA"] = null;

            newRow["AG"] = false;
        }

        void mg_ArtefactToManageEventExposed(object sender, ArtefactRefEventArgs e)
        {
            if (e.ArtefactRef != null)
                e.Cancel = dicoTreatedArtefact.ContainsKey(e.ArtefactRef.TypedId);
        }

        public void GetDirectoryInformations()
        {
            // Need to parse all Artefact Type
            foreach (SdmxArtefactType arType in Enum.GetValues(typeof(SdmxArtefactType)))
            {
                if (arType != SdmxArtefactType.None)
                {
                    DataSet dsArtefactType = proxyGroup.DirInfo(arType.ToString());
                    DataTable tb = dsArtefactType.Tables[0].Clone();
                    // Now copy all rows containing agency group ID
                    foreach (DataRow row in dsArtefactType.Tables[0].Rows)
                        if (row["AI"].ToString() == groupId)
                            tb.Rows.Add(row.ItemArray);

                    dicoDirInfo.Add(arType, tb);
                    dicoDirTreated.Add(arType, dsArtefactType.Tables[0].Clone());
                }
            }

        }

    }
}
